查看原文
其他

PE结构体中导出表/导入表解析——初阶

2018-01-27 Reginald 看雪学院



一、导出表解析




输出表位置,落在了.rdata段,




16000【5200】

17D70【6F70】
 

从而,可以知道17D70,输出表在磁盘中的偏移是6F70


在010里,Ctrl + G,输入6F70

这里,先看下导出表的数据结构,40B,


typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name; // DLL的名称地址
    DWORD   Base; // 索引基数
    DWORD   NumberOfFunctions; // 函数地址表大小
    DWORD   NumberOfNames; // 函数名表大小 == 函数序号表大小
    DWORD   AddressOfFunctions;     // 函数地址表——首地址
    DWORD   AddressOfNames;         // 函数名表——首地址
    DWORD   AddressOfNameOrdinals;  // 函数序号表——首地址
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;


那就从6F70的位置,开始,找40B,如下:




00 00 00 00

71 DB 67 5A 【时间戳】

00 00 【主版本】

00 00 【次版本】

C0 7D 01 00【DLL名称地址】

01 00 00 00 【索引基数】

04 00 00 00 【函数地址表大小】

04 00 00 00 【函数名表大小 == 函数序号表大小】

98 7D 01 00【函数地址表——首地址】

A8 7D 01 00 【函数名表——首地址】

B8 7D 01 00【函数序号表——首地址】


1、看DLL的名称是啥:地址17DC0【6FC0】,找到了我们自己的库dll_00.dll



2、再看下函数地址表中的元素,首地址17D98【6F98】,共有4个,地址,4B/个



如下所示:



3、再来看函数名表中的元素,首地址17DA8【6FA8】,共有4个,地址4B/个




这些都是地址值,要找到真正的函数名:


17DD0【6FD0】



17DD5【6FD5】



17DDA【6FDA】



17DCB【6FCB】



特别注意:函数名表,其实存放的也是地址值,RVA,这个只是我们自己找到的名称,方便起见,直接写的名字



4、接下来,看下函数序号表,首地址17DB8【6FB8】,4个,序号,2B/个




5、接下来,就分析分析:从这里,也可以看到,序号表里的值,并没有加上索引基数


最终,会得到如下结果:



6、验证下,我们的结果:成功了;




至于,索引基数,还没看到效果呢,————注意看下刚刚的LoadPe里的Ordinal那一列




部分代码:

#pragma once

#define WIN32DLL_EXPORTS

#ifdef __cplusplus
extern "C" {
#endif

#ifdef WIN32DLL_EXPORTS
#define WIN32DLL_API __declspec(dllexport)
#else
#define WIN32DLL_API __declspec(dllimport)
#endif

    WIN32DLL_API void Fun1();
    WIN32DLL_API void Fun2();
    WIN32DLL_API void Fun3();

#ifdef __cplusplus
}
#endif


def文件


LIBRARY;
EXPORTS;
    Fun4;



二、导入表解析


写一个测试程序,查看导入表RVA




输入表位置,落在了.idata段




1A000【7400】

1A1E8【75E8】


共20B


typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;                  // 0 if not
    DWORD   ForwarderChain;             
    DWORD   Name;
    DWORD   FirstThunk;                     // RVA to IAT
} IMAGE_IMPORT_DESCRIPTOR;





2C A3 01 00 【OriginalFirstThunk:INT(Import Name Table)导入名称表地址RVA】

00 00 00 00 

00 00 00 00 

54 A4 01 00【DLL名称(地址值)】

E0 A0 01 00【IAT(Import Address Table)导入地址表地址RVA】


1、首先看下DLL的名字,1A454【7854】




2、看下INT(OriginalFirstThunk):1A32C【772C】,全0结尾




函数名数组:


44 A4 01 00 ————1A444【7844】——————最高位为0,说明是名称导入的,不是序号导入的;

3C A4 01 00 ————1A43C【783C】——————

4C A4 01 00 ————1A44C【784C】——————

34 A4 01 00 ————1A434【7834】——————


注意:IAT和INT都指向下面的数据结构,4B


typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // PBYTE
        DWORD Function;             // PDWORD,导入函数的地址,在加载到内存后,这里才起作用
        DWORD Ordinal;              // 假如是序号导入的,会用到这里
        DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME,假如是函数名导入的,用到这里,它指向另外一个结构体:PIMGE_IMPORT_BY_NAME
    } u1;
} IMAGE_THUNK_DATA32;

// 如果是函数名导入的,AddressOfData会指向下面这个结构体
typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;
    CHAR   Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;


由上可知,函数名导入的,因此,上面的地址值,就会指向一个PIMAGE_IMPORT_BY_NAME的结构体:

【7844】Fun3



【783C】Fun2


【784C】Fun4


【7834】Fun1



3、看下IAT,1A0E0【74E0】全0结束,IAT和INT一样,都指向IMAGE_THUNK_DATA32结构体,4B



可见,最高位都是0,所以,也是名称导入的,另外,还可以发现,这个位置的值,和INT的值是一样的,因此,不再赘述了;

44 A4 01 00 

3C A4 01 00 

4C A4 01 00 

34 A4 01 00



 

#include <stdio.h>

extern "C" __declspec(dllimport) void Fun1();
extern "C" __declspec(dllimport) void Fun2();
extern "C" __declspec(dllimport) void Fun3();

// 如果是在def中导出的,需要如下声明
void Fun4();

#pragma comment(lib, "../Debug/dll_00.lib")

int main(int argc, char** argv) {
    Fun1();
    Fun2();
    Fun3();
    Fun4();

    getchar();

    return 0;
}



三、如果,修改def为


LIBRARY;
EXPORTS;
    Fun4 @1;


看下导入表里的INT/IAT:




可见,这里的一项,最高位为1,序号导入,这个序号,就是dll export的那个序号


至此,PE结构中,导入/导出表的介绍结束;


PS:I Dare to do sth I feared,作为一枚奋斗青年,也是一枚小白,最近在学习PE结构相关的知识,这篇帖子也算是自己的一个总结;希望能对需要的人以帮助;也期待大神们的更多指导;





本文由看雪论坛 Reginald 原创

转载请注明来自看雪社区



热门阅读


点击阅读原文/read,

更多干货等着你~


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存